package com.ccnf.web.handler;

import com.ccnf.core.bean.Response;
import com.ccnf.core.bean.StatusCode;
import com.ccnf.core.exception.BizException;
import com.ccnf.core.exception.NotFoundDataException;
import com.ccnf.core.exception.SQLOperationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import java.io.IOException;

@RestControllerAdvice(basePackages = "com.ccnf.web.controller")
@Slf4j
public class GlobalExceptionHandler {

    @ExceptionHandler({Exception.class})
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR, reason = "未知异常")
    public Response handleException(Exception e) {
        log.error("未知异常", e);
        String message = e.getCause() == null ? e.getMessage() : e.getCause().getMessage();
        return Response.failure(StatusCode.UNKNOWN_EXCEPTION, "未知异常: " + message);
    }

    @ExceptionHandler({RuntimeException.class})
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR, reason = "运行时异常")
    public Response handleRuntimeException(RuntimeException e) {
        log.error("未知异常", e);
        String message = e.getCause() == null ? e.getMessage() : e.getCause().getMessage();
        return Response.failure(StatusCode.RUNTIME_EXCEPTION, "运行时异常: " + message);
    }

    @ExceptionHandler({BizException.class})
    public Response handleBizException(BizException e) {
        String message = e.getMessage();
        log.info("BizException: " + message);
        return Response.failure(e.getErrorCode(), message);
    }

    @ExceptionHandler({SQLOperationException.class})
    public Response handleSQLOperationException(SQLOperationException e) {
        String message = e.getMessage();
        log.info("SQLOperationException: " + message);
        return Response.failure(StatusCode.SQL_OPERATION_FAILURE, message);
    }

    @ExceptionHandler({NotFoundDataException.class})
    public Response handleNotFoundDataException(NotFoundDataException e) {
        log.info("NotFoundDataException: " + e.getMessage());
        return Response.failure(StatusCode.DATA_NOT_FOUNT, e.getMessage());
    }

    @ExceptionHandler({BindException.class})
    public Response handleMethodArgumentNotValidException(BindException e) throws IOException {
        StringBuilder builder = new StringBuilder("请检查字段有效性：");
        e.getFieldErrors().forEach(error -> builder.append(error.getField() + error.getDefaultMessage()).append(", "));
        String errorMessage = builder.substring(0, builder.length() - 2);
        log.info("BindException: " + errorMessage);
        return Response.failure(StatusCode.PARAMETER_ERROR, builder.substring(0, builder.length() - 2));
    }

    @ExceptionHandler({MethodArgumentNotValidException.class})
    public Response handleMethodArgumentNotValidException(MethodArgumentNotValidException e) throws IOException {
        StringBuilder builder = new StringBuilder("请检查字段有效性：");
        e.getBindingResult().getFieldErrors().forEach(error -> builder.append(error.getField() + error.getDefaultMessage()).append(", "));
        String errorMessage = builder.substring(0, builder.length() - 2);
        log.info("MethodArgumentNotValidException: " + errorMessage);
        return Response.failure(StatusCode.PARAMETER_ERROR, errorMessage);
    }

    @ExceptionHandler({HttpMessageNotReadableException.class})
    public Response handleHttpMessageNotReadableException(HttpMessageNotReadableException e) throws IOException {
        log.info("HttpMessageNotReadableException: ",  e);
        return Response.failure(StatusCode.PARAMETER_ERROR, e.getMessage());
    }

    @ExceptionHandler({MethodArgumentTypeMismatchException.class})
    public Response handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) throws IOException {
        log.info("MethodArgumentTypeMismatchException: ", e);
        return Response.failure(StatusCode.ARGUMENT_TYPE_MISMATCH, e.getParameter().getParameterName() + "参数不合法");
    }
}